using MessagePack;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using CNative.Cloud.Codec.MessagePack.Utilities;
using CNative.Cloud.CPlatform.Utilities;
using System;
using System.Runtime.CompilerServices;
using System.Collections.Generic;
using System.Linq;

namespace CNative.Cloud.Codec.MessagePack.Messages
{
    [MessagePackObject]
    public class DynamicItem
    {
        #region Constructor

        public DynamicItem()
        { }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public DynamicItem(object value)
        {
            if (value == null)
                throw new ArgumentNullException(nameof(value));

            var valueType = value.GetType();
            var code = Type.GetTypeCode(valueType);

            if (code != TypeCode.Object && valueType.BaseType!=typeof(Enum))
                TypeName = valueType.FullName;
            else
                TypeName = valueType.AssemblyQualifiedName;

            if (valueType == UtilityType.JObjectType || valueType == UtilityType.JArrayType)
                Content = SerializerUtilitys.Serialize(value.ToString());
            else
                Content = SerializerUtilitys.Serialize(value);
        }

        #endregion Constructor

        #region Property

        [Key(0)]
        public string TypeName { get; set; }

        [Key(1)]
        public byte[] Content { get; set; }
        #endregion Property

        #region Public Method
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public object Get()
        {
            if (Content == null || TypeName == null)
                return null;

            var typeName = Type.GetType(TypeName);
            if (typeName == UtilityType.JObjectType || typeName == UtilityType.JArrayType)
            {
                var content = SerializerUtilitys.Deserialize<string>(Content);
                return JsonConvert.DeserializeObject(content, typeName);
            }
            else
            {
                if (typeName == null)
                {
                    typeName = GetType(TypeName);
                }
                return SerializerUtilitys.Deserialize(Content, typeName);
            }
        }

        [IgnoreMember]
       static System.Collections.Concurrent.ConcurrentDictionary<string, Type> dicType = new System.Collections.Concurrent.ConcurrentDictionary<string, Type>();
        private Type GetType(string typeName)
        {
            if (dicType.TryGetValue(typeName, out Type type1)) return type1;

            var assemblies = AppDomain.CurrentDomain.GetAssemblies();
            foreach (var assembly in assemblies)
            {
                var allTypes = assembly.GetTypes();
                var type = allTypes.FirstOrDefault(t => t.Name == typeName || typeName.Contains(t.FullName));
                if (type != null)
                {
                    dicType[typeName] = type;
                    return type;
                }
                //var aa = assembly.GetReferencedAssemblies();
                //foreach (var sas in aa)
                //{
                //    try
                //    {
                //        allTypes = System.Reflection.Assembly.Load(sas).GetTypes();
                //        type = allTypes.FirstOrDefault(t => t.Name == typeName);
                //        if (type != null)
                //        {
                //            return type;
                //        }
                //    }
                //    catch (Exception ex)
                //    {
                //        CPlatform.ConsoleC.WriteLine(ex);
                //    }
                //}
            }
            throw new KeyNotFoundException("Can't find type "+ typeName);
        }
        #endregion Public Method
    }
}
